﻿#include "DANodeGraphicsScene.h"
#include <QGraphicsSceneMouseEvent>
#include <QScopedPointer>
#include "DAStandardNodeLinkGraphicsItem.h"
class DANodeGraphicsScenePrivate
{
    DA_IMPL_PUBLIC(DANodeGraphicsScene)
public:
    DANodeGraphicsScenePrivate(DANodeGraphicsScene *p);
    bool _isStartLink;
    QScopedPointer<DAStandardNodeLinkGraphicsItem> _linkingItem;
    QPointF _lastMouseScenePos;
};

DANodeGraphicsScenePrivate::DANodeGraphicsScenePrivate(DANodeGraphicsScene *p) : q_ptr(p), _isStartLink(false) {}

DANodeGraphicsScene::DANodeGraphicsScene(QObject *p) : QGraphicsScene(p), d_ptr(new DANodeGraphicsScenePrivate(this))
{
    initConnect();
}

DANodeGraphicsScene::DANodeGraphicsScene(const QRectF &sceneRect, QObject *p)
    : QGraphicsScene(sceneRect, p), d_ptr(new DANodeGraphicsScenePrivate(this))
{
    initConnect();
}

DANodeGraphicsScene::DANodeGraphicsScene(qreal x, qreal y, qreal width, qreal height, QObject *p)
    : QGraphicsScene(x, y, width, height, p), d_ptr(new DANodeGraphicsScenePrivate(this))
{
    initConnect();
}

DANodeGraphicsScene::~DANodeGraphicsScene() {}

bool DANodeGraphicsScene::isStartLink() const
{
    return (d_ptr->_isStartLink);
}

QPointF DANodeGraphicsScene::getCurrentMouseScenePos() const
{
    return (d_ptr->_lastMouseScenePos);
}

/**
 * @brief 获取选中的NodeGraphicsItem,如果没有返回nullptr，如果选中多个，返回第一个
 * @return
 */
DAAbstractNodeGraphicsItem *DANodeGraphicsScene::getSelectedNodeGraphicsItem() const
{
    QList<QGraphicsItem *> sits = selectedItems();
    for (QGraphicsItem *i : sits) {
        if (DAAbstractNodeGraphicsItem *gi = dynamic_cast<DAAbstractNodeGraphicsItem *>(i)) {
            return gi;
        }
    }
    return nullptr;
}

/**
 * @brief 获取选中的NodeGraphicsItem,如果没有返回一个空list
 * @return
 */
QList<DAAbstractNodeGraphicsItem *> DANodeGraphicsScene::getSelectedNodeGraphicsItems() const
{
    QList<DAAbstractNodeGraphicsItem *> res;
    QList<QGraphicsItem *> sits = selectedItems();
    for (QGraphicsItem *i : sits) {
        if (DAAbstractNodeGraphicsItem *gi = dynamic_cast<DAAbstractNodeGraphicsItem *>(i)) {
            res.append(gi);
        }
    }
    return res;
}
/**
 * @brief 获取选中的NodeLinkGraphicsItem,如果没有返回nullptr，如果选中多个，返回第一个
 * @return
 */
DAAbstractNodeLinkGraphicsItem *DANodeGraphicsScene::getSelectedNodeLinkGraphicsItem() const
{
    QList<QGraphicsItem *> sits = selectedItems();
    for (QGraphicsItem *i : sits) {
        if (DAAbstractNodeLinkGraphicsItem *gi = dynamic_cast<DAAbstractNodeLinkGraphicsItem *>(i)) {
            return gi;
        }
    }
    return nullptr;
}
/**
 * @brief 获取选中的NodeLinkGraphicsItem,如果没有返回一个空list
 * @return
 */
QList<DAAbstractNodeLinkGraphicsItem *> DANodeGraphicsScene::getSelectedNodeLinkGraphicsItems() const
{
    QList<DAAbstractNodeLinkGraphicsItem *> res;
    QList<QGraphicsItem *> sits = selectedItems();
    for (QGraphicsItem *i : sits) {
        if (DAAbstractNodeLinkGraphicsItem *gi = dynamic_cast<DAAbstractNodeLinkGraphicsItem *>(i)) {
            res.append(gi);
        }
    }
    return res;
}

void DANodeGraphicsScene::initConnect()
{
    qRegisterMetaType<DANodeLinkPoint>("FCNodeLinkPoint");
    connect(this, &DANodeGraphicsScene::nodeItemLinkPointSelected, this, &DANodeGraphicsScene::onNodeItemLinkPointSelected);
}

void DANodeGraphicsScene::callNodeItemLinkPointSelected(DAAbstractNodeGraphicsItem *item,
                                                        const DANodeLinkPoint &lp,
                                                        QGraphicsSceneMouseEvent *event)
{
    qDebug() << item->getNodeName() << " selecte " << lp;
    emit nodeItemLinkPointSelected(item, lp, event);
}

/**
 * @brief itemlink都没用节点连接时会调用这个函数，发出
 * @param link
 */
void DANodeGraphicsScene::callNodeItemLinkIsEmpty(DAAbstractNodeLinkGraphicsItem *link)
{
    removeItem(link);
    emit nodeLinkItemIsEmpty(link);
}

void DANodeGraphicsScene::onNodeItemLinkPointSelected(DAAbstractNodeGraphicsItem *item, const DANodeLinkPoint &lp, QGraphicsSceneMouseEvent *event)
{
    if (event->buttons().testFlag(Qt::LeftButton)) {
        if (isStartLink()) {
            //说明此时处于开始连接状态，接收到点击需要判断是否接受
            if (lp.isOutput() && d_ptr->_linkingItem.isNull()) {
                //连接的结束从in结束，out就退出
                event->ignore();
                return;
            }
            //此时连接到to点
            if (d_ptr->_linkingItem->attachTo(item, lp)) {
                //连接成功，把item脱离管理
                d_ptr->_linkingItem->updateBoundingRect();
                d_ptr->_linkingItem.take();
                d_ptr->_isStartLink = false;
            }
        } else {
            //说明此时处于正常状态，判断是否开始连线
            if (lp.isInput()) {
                //连接的开始从out开始，in就退出
                event->ignore();
                return;
            }
            //此时说明开始进行连线
            d_ptr->_isStartLink = true;
            d_ptr->_linkingItem.reset(new DAStandardNodeLinkGraphicsItem());
            if (!d_ptr->_linkingItem->attachFrom(item, lp)) {
                //连接不成功
                d_ptr->_linkingItem.reset();
                d_ptr->_isStartLink = false;
                return;
            }
            //把item加入
            addItem(d_ptr->_linkingItem.get());
            d_ptr->_linkingItem->setPos(item->mapToScene(lp.position));
            d_ptr->_linkingItem->updateBoundingRect();
        }
    } else {
        //除开左键的所有按键都是取消
        if (isStartLink()) {
            qDebug() << "will remove link";
            d_ptr->_isStartLink = false;
            removeItem(d_ptr->_linkingItem.get());
            d_ptr->_linkingItem.reset();
        }
    }
}

void DANodeGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
    if (!mouseEvent->buttons().testFlag(Qt::LeftButton)) {
        //除开左键的所有按键都是取消
        if (isStartLink()) {
            qDebug() << "will remove link";
            d_ptr->_isStartLink = false;
            removeItem(d_ptr->_linkingItem.get());
            d_ptr->_linkingItem.reset();
        }
    }
    QGraphicsScene::mousePressEvent(mouseEvent);
}

void DANodeGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
    if (nullptr == mouseEvent) {
        return;
    }
    d_ptr->_lastMouseScenePos = mouseEvent->scenePos();
    if (isStartLink() && !(d_ptr->_linkingItem.isNull())) {
        //此时正值连接中，把鼠标的位置发送到link中
        d_ptr->_linkingItem->updateBoundingRect();
    }
    QGraphicsScene::mouseMoveEvent(mouseEvent);
}
